using System;
using System.Collections;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web.UI;
using System.Web;
using System.Text;
using System.IO;

namespace Blazing.Web.Controls
{
	/// <summary>
	/// A web control for displaying OptGroups in a drop down list
	/// </summary>
    [DefaultProperty("Size"), ToolboxData("<{0}:OptGroupDropDownList runat=\"server\"></{0}:OptGroupDropDownList>"), SerializableAttribute()]
	public class OptGroupDropDownList : System.Web.UI.WebControls.DropDownList
	{

		/// <summary>
		/// A structure for internally collating list items
		/// </summary>
		protected struct OptGroupStruct
		{
			public string Name;
			public ArrayList List;

			public OptGroupStruct(string pName)
			{
                Name = pName;
				List = new ArrayList();
			}
		}

		/// <summary>
		/// Gets the value of the first selectable item
		/// </summary>
		public string FirstItemValue
		{
			get
			{
				string[] mStr;

				foreach(ListItem it in Items)
				{
					mStr = it.Text.Split('|');
					if(mStr.Length > 1 && !mStr[0].Equals("optgroup"))
					{
						return it.Value;
					}
				}

				return string.Empty;
			}
		}

		/// <summary>
		/// Gets the index of the first selectable item
		/// </summary>
		public int FirstItemIndex
		{
			get
			{
				string[] mStr;
				int index=0;
				foreach(ListItem it in Items)
				{
					mStr = it.Text.Split('|');
					if(mStr.Length > 1 && !mStr[0].Equals("optgroup"))
					{
                        return index;						
					}
					index++;                
				}
				return -1;
			}
		}

		/// <summary>
		/// Creates an OptGroup and Collects it's items
		/// </summary>
		private ArrayList OptGroups
		{
			get
			{
				ArrayList ar = new ArrayList();
				OptGroupStruct opt = new OptGroupStruct("");
				OptGroupStruct none = new OptGroupStruct("");
				none.Name = "";
				string[] mStr;
				foreach(ListItem it in Items)
				{
					mStr = it.Text.Split('|');
					if(mStr.Length > 1 && mStr[0].Equals("optgroup"))
					{
						opt = new OptGroupStruct(mStr[1]);
						ar.Add(opt);
					}
					else //add optgroup item
					{
						mStr = it.Text.Split('|');
						if(mStr.Length > 1 && mStr[0].Equals(opt.Name))
						{
							opt.List.Add(it);                            
						}
						else //its a regular item
						{
							none.List.Add(it);                                                                               
						}
					}
				}
				if(none.List.Count > 0)
					ar.Add(none);
				return ar;
			}
		}

        public int Size
        {
            get
            {
                object obj = ViewState["Size"];
                if (obj != null)
                    return (int)obj;
                return -1;
            }
            set
            {
                ViewState["Size"] = value;
            }
        }

		/// <summary>
		/// Default constructor
		/// </summary>
		public OptGroupDropDownList() : base()
		{
            
		}

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (Size > -1)
            {
                Attributes.Add("size", Size + "");
                Attributes.Add("multiple", null);
            }
        }

        protected override void VerifyMultiSelect()
        {
            //base.VerifyMultiSelect();
        }

        protected override bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            string val = postCollection[postDataKey];
            if (val.IndexOf(',') > -1)
            {
                bool retval = true;
                string[] split = val.Split(',');
                foreach (ListItem li in this.Items)
                {
                    li.Selected = false;
                    if (Array.IndexOf<string>(split, li.Value) > -1)
                    {
                        li.Selected = true;
                    }
                }
                return retval;
            }
            else
            {
                return base.LoadPostData(postDataKey, postCollection);
            }
        }

		/// <summary>
		/// Renders groups and items to html, can also render regular (non grouped) items
		/// </summary>
		protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
		{
			//render optgroups
			int hasSubstr;
			foreach(OptGroupStruct str in OptGroups)
			{
				if(str.Name.Length > 0)
				{
					writer.WriteBeginTag("optgroup");
					writer.WriteAttribute("label", str.Name, true);
					writer.Write(">");
					writer.WriteLine();
				}
				foreach(ListItem li in str.List)
				{
                    writer.WriteBeginTag("option");
					if(li.Selected)
						writer.WriteAttribute("selected", "selected", false);
					writer.WriteAttribute("value", li.Value, true);
					li.Attributes.Render(writer);
					writer.Write(">");
					hasSubstr = li.Text.IndexOf("|");
					HttpUtility.HtmlEncode((hasSubstr>-1?li.Text.Substring(hasSubstr+1):li.Text), writer);
					writer.WriteEndTag("option");
					writer.WriteLine();
				}
				if(str.Name.Length > 0)
				{
					writer.WriteEndTag("optgroup");
					writer.WriteLine();
				}
			}
		}

		/// <summary>
		/// Adds a new optgroup, note: | chars should not be used in item or group names
		/// </summary>
		public void AddOptGroup(string pName, ListItem[] pItems)
		{
			Items.Add("optgroup|"+pName);
			foreach(ListItem it in pItems)
			{
                Items.Add( new ListItem(pName+"|"+it.Text,it.Value));
			}
		}

		/// <summary>
		/// Removes an optgroup
		/// </summary>
		public void RemoveOptionGroup(string pName)
		{
			string[] mStr;
			foreach(ListItem it in Items)
			{
				mStr = it.Text.Split('|');
				if(mStr.Length > 1 && mStr[0].Equals("optgroup") && mStr[1].Equals(pName))
				{
					Items.Remove(it);
				}
				else if(mStr.Length > 1 && mStr[0].Equals(pName))
				{
                    Items.Remove(it);
				}
			}
		}
	}
}
